// 给你一个整数数组 nums ，和一个表示限制的整数 limit，请你返回最长连续子数组的长度，
// 该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。

// 如果不存在满足条件的子数组，则返回 0 。

const longestSubarray = function (nums: number[], limit: number): number {
    let left = 0;
    let right = 0;
    let res = 0;
    const minQueue: number[] = [];// 单调递减队列
    const maxQueue: number[] = [];// 单调递增队列
    // 滑动窗口过程
    while (right < nums.length) {
        // 舍弃单调队列中的无用数据以保持单调性
        while (minQueue.length > 0 && minQueue[minQueue.length - 1] > nums[right]) {
            minQueue.pop();
        }
        while (maxQueue.length > 0 && maxQueue[maxQueue.length - 1] < nums[right]) {
            maxQueue.pop();
        }
        // 当前元素入队
        minQueue.push(nums[right]);
        maxQueue.push(nums[right]);
        // 计算当前限制
        let currLimit = maxQueue[0] - minQueue[0];
        // 左指针滑动以满足题目要求
        while (currLimit > limit && minQueue.length > 0 && maxQueue.length > 0) {
            if (nums[left] === minQueue[0]) {
                minQueue.shift();
            }
            if (nums[left] === maxQueue[0]) {
                maxQueue.shift();
            }
            left++;
            currLimit = maxQueue[0] - minQueue[0];
        }
        // 右指针滑动，实际为左闭右开
        right++;
        res = Math.max(res, right - left);
    }
    return res;
};


// 这道题目通过正确的方法解答就会非常的容易
// 本题是求最大连续子区间，可以使用滑动窗口方法。
// 滑动窗口的限制条件是：窗口内最大值和最小值的差不超过给定限制。
// 这个题目的难点在于快速地求滑动窗口内的最大值和最小值
// 因为知道了窗口内的最大值和最小值就可以方便的求得绝对差的最大值
// 因此我们也可以分别使用两个单调队列解决
// 在实际代码中，我们使用一个单调递增的队列维护最小值，一个单调递减的队列维护最大值。
// 这样我们只需要计算两个队列的队首的差值，即可知道当前窗口是否满足条件。
// 单调队列的特点在于它能严格保持窗口内数据的单调性而舍去不必要且不可能用到的数据
// 例如5、2、3、4中，经过单调队列处理变为 5、4，而在这里的2、3是不会用到的无用数据
// 之后套用滑动窗口的模板即可。
